﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Threading;

namespace Zip
{
    public class ProcessFilesForm1
    {
  /*   
        public List<FileHeader> ZipDir;
        public InflateZipFile Inflate;
        public DeflateZipFile Deflate;
        public Boolean UpdateMode;
        public String RootDir;
        public Int32 CompLevel;

        private Int32 DirIndex;
        private Timer stateTimer;
        private Boolean AbortFlag;
        private Int32 ErrorCount;
        private Boolean flagDisplay;
        */
        public static FileStream fs;
        Byte[] info;
        public static Timer stateTimer1;
        public static AutoResetEvent autoEvent1;

        /////////////////////////////////////////////////////////////////
        // Constructor
        /////////////////////////////////////////////////////////////////

        public ProcessFilesForm1()
        {

        }

        public void OnLoad()
        {

                fs = File.OpenWrite("Ziptrace.txt");
                UTF8Encoding utf8 = new UTF8Encoding();
                string ss = DateTime.Now.ToString() + "\n";
 
                 info = utf8.GetBytes(ss);
                fs.Write(info,0,info.Length);

            // create extract timer
                AutoResetEvent autoEvent = new AutoResetEvent(false);
                autoEvent1 = autoEvent;
                
                ProcessFilesForm2 process = new ProcessFilesForm2();

                // Create an inferred delegate that invokes methods for the timer.
                TimerCallback tcb = process.OnExtractTimer;

                // Create a timer that signals the delegate to invoke  
                // CheckStatus after one second, and every 1/4 second  

                Timer stateTimer = new Timer(tcb, autoEvent, 10,10);
                stateTimer1 = stateTimer;

            return;
        }

    }

    public class ProcessFilesForm2
    {
        
        public static List<FileHeader> ZipDir;
        public static InflateZipFile Inflate;
        public static DeflateZipFile Deflate;
        public static Boolean UpdateMode;
        public String RootDir;
        public Int32 CompLevel;
        
        private Int32 DirIndex;
        private Boolean AbortFlag;
        private Int32 ErrorCount;
        private Boolean flagDisplay;

//       private FileStream fs;
        Byte[] info;

        /////////////////////////////////////////////////////////////////
        // Constructor
        /////////////////////////////////////////////////////////////////

        public ProcessFilesForm2()
        {
            DirIndex = 0;
            ErrorCount = 0;
            AbortFlag = false;
            flagDisplay = true;

        }

        /////////////////////////////////////////////////////////////////
        // Extract Timer
        /////////////////////////////////////////////////////////////////

        public void OnExtractTimer( Object stateInfo )
        {
            // stop the timer
            ProcessFilesForm1.stateTimer1.Change(Timeout.Infinite, 10);

            AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;

            // test for end
            if (AbortFlag || DirIndex == ZipDir.Count)
            {
    //            if(flagDisplay) ExitButton.Text = "Exit";
                ProcessFilesForm1.fs.Close();
                ProcessFilesForm1.stateTimer1.Dispose();
                return;
            }

            // display current file
            if (flagDisplay) DispStatus(ZipDir[DirIndex].FileName);

            // update file
           
            if (UpdateMode)
            {
   //             if (UpdateFile()) ErrorCount++;
            }
            
            // extract file
            else
            {
                if (ExtractFile()) ErrorCount++;
            }

            // update index
            DirIndex++;

            //* display progress
            if (flagDisplay)
            {
                string ProgressLabel = String.Format("{0}/{1}", DirIndex, ZipDir.Count + "\n");
                UTF8Encoding utf8 = new UTF8Encoding();
                info = utf8.GetBytes(ProgressLabel);
                ProcessFilesForm1.fs.Write(info, 0, info.Length);
                if (ErrorCount > 0)
                {
                    string ErrorLabel = "errore   " + ErrorCount.ToString() + "\n";
                    UTF8Encoding utf81 = new UTF8Encoding();
                    info = utf81.GetBytes(ErrorLabel);
                    ProcessFilesForm1.fs.Write(info, 0, info.Length);
                    Extract1.result = ErrorCount;
                }
                if (ErrorCount == 0 && (DirIndex == ZipDir.Count))
                {
                    ProcessFilesForm1.fs.Close();
                    ProcessFilesForm1.stateTimer1.Dispose();
                    Extract1.result = 0;
                    autoEvent.Set();
                    return;
                }
            }
            
            // restart the timer
            ProcessFilesForm1.stateTimer1.Change(0,10);
        }

        /////////////////////////////////////////////////////////////////
        // Extract file
        /////////////////////////////////////////////////////////////////

        private Boolean ExtractFile()
        {
            // translate to file header
            FileHeader FH = ZipDir[DirIndex];

            // test skip read only
            if (ProgramState.State.SkipReadOnly && (FH.FileAttr & FileAttributes.ReadOnly) != 0)
            {
                AppendStatus("Skip read only\n");
                return (true);
            }

            // test skip hidden file
            if (ProgramState.State.SkipHidden && (FH.FileAttr & FileAttributes.Hidden) != 0)
            {
                AppendStatus("Skip hidden file\n");
                return (true);
            }

            // test skip system file
            if (ProgramState.State.SkipSystem && (FH.FileAttr & FileAttributes.System) != 0)
            {
                AppendStatus("Skip system file");
                return (true);
            }

            // file name
            String FileName = (FH.Path && ProgramState.State.IgnoreFolderInfo) ?
                FH.FileName.Substring(FH.FileName.LastIndexOf('\\') + 1) : FH.FileName;

            // full ourput file name
            String OutputFile = ProgramState.State.ExtractToFolder + "\\" + FileName;

            // path part of file name
            Int32 Ptr = OutputFile.LastIndexOf('\\');

            // we have a path, make sure path exists
            if (Ptr >= 0)
            {
                // skip older files
                if (ProgramState.State.SkipOlder)
                {
                    // exiting file
                    DateTime ExistingFileTime = File.GetLastWriteTime(OutputFile);

                    // compressed file
                    // convert dos file date and time to DateTime format
                    DateTime CompFileTime = new DateTime(1980 + ((FH.FileDate >> 9) & 0x7f), (FH.FileDate >> 5) & 0xf, FH.FileDate & 0x1f,
                        (FH.FileTime >> 11) & 0x1f, (FH.FileTime >> 5) & 0x3f, 2 * (FH.FileTime & 0x1f));

                    // compare times
                    if (CompFileTime < ExistingFileTime)
                    {
                        AppendStatus("Skip too old\n");
                        return (true);
                    }
                }

                // make sure directory exists
                if (!Directory.Exists(OutputFile.Substring(0, Ptr)))
                {
                    // make new folder
                    try
                    {
                        Directory.CreateDirectory(OutputFile.Substring(0, Ptr));
                    }
                    catch
                    {
                        AppendStatus("Path Error\n");
                        return (true);
                    }
                }

                // directory
                if ((FH.FileAttr & FileAttributes.Directory) != 0)
                {
                    AppendStatus("Dir-OK\n");
                    return (false);
                }
            }

            // test if file exists
            if (File.Exists(OutputFile))
            {
                // no overwrite
                if (ProgramState.State.Overwrite == (Int32)OverwriteFiles.No)
                {
                    AppendStatus("No overwrite");
                    return (true);
                }

                // ask overwrite permission
                if (ProgramState.State.Overwrite == (Int32)OverwriteFiles.Ask)
                {
           //         if (MessageBox.Show(this, "Do you want to overwrite: " + OutputFile + " ?\n(Press Cancel to abort extraction)", "Overwrite warning",
             //           MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question) == DialogResult.Cancel)
                    {
                        AppendStatus("No overwrite");
                        return (true);
                    }
                }

                // check for read only file
                if (!ProgramState.State.SkipReadOnly)
                {
                    FileAttributes Attr = File.GetAttributes(OutputFile);
                    if ((Attr & FileAttributes.ReadOnly) != 0)
                    {
                        try
                        {
                            File.SetAttributes(OutputFile, Attr & ~FileAttributes.ReadOnly);
                        }
                        catch { }
                    }
                }

                // delete file
                try
                {
                    File.Delete(OutputFile);
                }
                catch
                {
                    AppendStatus("Overwrite failed");
                    return (true);
                }
            }

            // decompress file
            if (Inflate.DecompressZipFile(FH, null, OutputFile, true, true))
            {
                Trace.Write("Decompression Error\n" + Inflate.ExceptionStack[0] + "\n" + Inflate.ExceptionStack[1]);
                // Version 1.1 fix Deflate.ExceptionStack[0] was changed to Inflate.ExceptionStack[0]
                AppendStatus("Decompression failed [" + Inflate.ExceptionStack[0] + "]\n");
                return (true);
            }

            // successful return
            AppendStatus("File-OK\n");
            return (false);
        }

        /////////////////////////////////////////////////////////////////
        // Update file
        /////////////////////////////////////////////////////////////////
/*
        private Boolean UpdateFile()
        {
            // translate to file header
            FileHeader FH = ZipDir[DirIndex];

            String FullFileName = RootDir.EndsWith("\\") ? RootDir + FH.FileName : RootDir + "\\" + FH.FileName;

            // save directory name in zip file
            if ((FH.FileAttr & FileAttributes.Directory) != 0)
            {
                if (Deflate.SaveDirectoryPath(FullFileName, FH.FileName))
                {
                    Trace.Write("Save directory path error\n" + Deflate.ExceptionStack[0] + "\n" + Deflate.ExceptionStack[1]);
                    AppendStatus("Save directory failed [" + Deflate.ExceptionStack[0] + "]");
                    return (true);
                }
            }

            // compress file
            else
            {
                Deflate.CompressionLevel = CompLevel;
                if (Deflate.Compress(FullFileName, FH.FileName))
                {
                    Trace.Write("Compression Error\n" + Deflate.ExceptionStack[0] + "\n" + Deflate.ExceptionStack[1]);
                    AppendStatus("Compression failed [" + Deflate.ExceptionStack[0] + "]");
                    return (true);
                }
            }

            // successful return
            AppendStatus("OK");
            return (false);
        }
        */
        ////////////////////////////////////////////////////////////////////
        // Display Status
        ////////////////////////////////////////////////////////////////////

        private void DispStatus
                (
                String Message
                )
        {
            UTF8Encoding utf8 = new UTF8Encoding();
            info = utf8.GetBytes(Message + "\n");
            ProcessFilesForm1.fs.Write(info, 0, info.Length);
            return;
        }
        
        ////////////////////////////////////////////////////////////////////
        // Append Status
        ////////////////////////////////////////////////////////////////////

        private void AppendStatus ( String Message )
        {
            UTF8Encoding utf8 = new UTF8Encoding();
            info = utf8.GetBytes(Message + "\n");
            ProcessFilesForm1.fs.Write(info, 0, info.Length);
            return;
        }

        /////////////////////////////////////////////////////////////////
        // Abort/Exit button
        /////////////////////////////////////////////////////////////////

        private void OnAbort
                (
                object sender,
                EventArgs e
                )
        {
            // test for end
            if (AbortFlag || DirIndex == ZipDir.Count)
            {
                return;
            }
            else
            {
                AbortFlag = true;
            }
            return;
        }

        /////////////////////////////////////////////////////////////////
        // Resize screen
        /////////////////////////////////////////////////////////////////
/*
        private void OnResize
                (
                object sender,
                EventArgs e
                )
        {
            // protect against minimize button
            if (ClientSize.Width == 0) return;

            // exit button
            ButtonsGroupBox.Left = ClientSize.Width / 2 - ButtonsGroupBox.Width / 2;
            ButtonsGroupBox.Top = ClientSize.Height - ButtonsGroupBox.Height;

            // status list box
            ListBox.Width = ClientSize.Width - 2 * ListBox.Left;
            ListBox.Height = ButtonsGroupBox.Top - ListBox.Top;

            // exit
            return;
        }
*/
    }
}
